<!DOCTYPE HTML>
<html lang="zh-CN">

<head><meta name="generator" content="Hexo 3.9.0">
    <!-- hexo-inject:begin --><!-- hexo-inject:end --><!--Setting-->
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
    <meta http-equiv="Cache-Control" content="no-siteapp">
    <meta http-equiv="Cache-Control" content="no-transform">
    <meta name="renderer" content="webkit|ie-comp|ie-stand">
    <meta name="apple-mobile-web-app-capable" content="AncyBlog">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">
    <meta name="format-detection" content="telephone=no,email=no,adress=no">
    <meta name="browsermode" content="application">
    <meta name="screen-orientation" content="portrait">
    <meta name="theme-version" content="1.2.3">
    <meta name="root" content="/">
    <link rel="dns-prefetch" href="http://www.anciety.de">

    <script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js">
    </script>
    <!--SEO-->

<meta name="keywords" content="learning,fuzz">


<meta name="description" content="AFL 浅读
AFL 基本思路
AFL 作为一款 fuzz 工具，与直接输入混乱数据相比，主要是加入了对控制流的理解，通过使用共享内存，将控制流信息写入到该共享内存中。通过利用控制流信息，可以更...">


<meta name="robots" content="all">
<meta name="google" content="all">
<meta name="googlebot" content="all">
<meta name="verify" content="all">
    <!--Title-->

<title>
    
    AFL 浅读 |
    
    AncyBlog
</title>

<link rel="alternate" href="/atom.xml" title="AncyBlog" type="application/atom+xml">


<link rel="icon" href="/favicon.png">

    

<link rel="stylesheet" href="/css/bootstrap.min.css?rev=3.3.7">
<link rel="stylesheet" href="/css/font-awesome.min.css?rev=4.7.0">
<link rel="stylesheet" href="/css/style.css?rev=@@hash">
    



<script type="text/javascript" src="https://tajs.qq.com/stats?sId=66471611" charset="UTF-8"></script><!-- hexo-inject:begin --><!-- hexo-inject:end -->


    

</head>
</html>
<!--[if lte IE 8]>
<style>
    html{ font-size: 1em }
</style>
<![endif]-->
<!--[if lte IE 9]>
<div style="ie">你使用的浏览器版本过低，为了你更好的阅读体验，请更新浏览器的版本或者使用其他现代浏览器，比如Chrome、Firefox、Safari等。</div>
<![endif]-->
<body>
    <!-- hexo-inject:begin --><!-- hexo-inject:end --><header class="main-header"  style="background-image:url(
    https://www.anciety.de/img/banner.jpg)"
     >
    <div class="main-header-box">
        <a class="header-avatar" href="/" title='Anciety'>
            <img src="/img/avatar.jpg" alt="logo头像" class="img-responsive center-block">
        </a>
        <div class="branding">
            <!--<h2 class="text-hide">Snippet主题,从未如此简单有趣</h2>-->
            
            <h2>
                Hacked By Swing
            </h2>
            
        </div>
    </div>
</header>
    <nav class="main-navigation">
    <div class="container">
        <div class="row">
            <div class="col-sm-12">
                <div class="navbar-header"><span class="nav-toggle-button collapsed pull-right" data-toggle="collapse" data-target="#main-menu" id="mnav">
                        <span class="sr-only"></span>
                        <i class="fa fa-bars"></i>
                    </span>
                    <a class="navbar-brand" href="http://www.anciety.de">
                        AncyBlog</a>
                </div>
                <div class="collapse navbar-collapse" id="main-menu">
                    <ul class="menu">
                        
                        <li role="presentation" class="text-center">
                            <a href="/"><i class="fa "></i>
                                首页</a>
                        </li>
                        
                        <li role="presentation" class="text-center">
                            <a href="/categories/writeups/"><i class="fa "></i>
                                writeups</a>
                        </li>
                        
                        <li role="presentation" class="text-center">
                            <a href="/categories/学习/"><i class="fa "></i>
                                学习</a>
                        </li>
                        
                        <li role="presentation" class="text-center">
                            <a href="/categories/问题解决/"><i class="fa "></i>
                                问题解决</a>
                        </li>
                        
                        <li role="presentation" class="text-center">
                            <a href="/categories/扯淡/"><i class="fa "></i>
                                扯淡</a>
                        </li>
                        
                        <li role="presentation" class="text-center">
                            <a href="/archives/"><i class="fa "></i>
                                时间轴</a>
                        </li>
                        
                    </ul>
                </div>
            </div>
        </div>
    </div>
</nav>
    <section class="content-wrap">
        <div class="container">
            <div class="row">
                <main class="col-md-8 main-content m-post">
                    <p id="process"></p>
<article class="post">
    <div class="post-head">
        <h1 id="AFL 浅读">
            
            AFL 浅读
            
        </h1>
        <div class="post-meta">
    
    <span class="categories-meta fa-wrap">
        <i class="fa fa-folder-open-o"></i>
        <a class="category-link" href="/categories/学习/">学习</a>
    </span>
    
    
    <span class="fa-wrap">
        <i class="fa fa-tags"></i>
        <span class="tags-meta">
            
            <a class="tag-link" href="/tags/fuzz/">fuzz</a> <a class="tag-link" href="/tags/learning/">learning</a>
            
        </span>
    </span>
    
    
    
    <span class="fa-wrap">
        <i class="fa fa-clock-o"></i>
        <span class="date-meta">
            2019/10/08</span>
    </span>
    
    <span class="fa-wrap">
        <i class="fa fa-eye"></i>
        <span id="busuanzi_value_page_pv"></span>
    </span>
    
    
</div>
        
        
    </div>
    
    <div class="post-body post-content">
        <h1 id="afl-浅读">AFL 浅读</h1>
<h2 id="afl-基本思路">AFL 基本思路</h2>
<p>AFL 作为一款 fuzz 工具，与直接输入混乱数据相比，主要是加入了对控制流的理解，通过使用共享内存，将控制流信息写入到该共享内存中。通过利用控制流信息，可以更好的引导变异，使得变异更加倾向于使用能够方发现新路径的输入数据，从而提高的 fuzz 的效率。</p>
<h2 id="afl-大致流程">AFL 大致流程</h2>
<ol type="1">
<li>加载用户提供的初始输入样本，放入队列中</li>
<li>从队列中取出下一个输入文件</li>
<li>尝试缩减输入样本的大小而不影响程序行为</li>
<li>使用一些方法对文件进行变异</li>
<li>如果变异结果导致走入新的路径，则记录到队列中</li>
<li>回到第二步</li>
</ol>
<p>整个步骤的理解还算比较简单。</p>
<h2 id="一些细节">一些细节</h2>
<h3 id="使用过程">使用过程</h3>
<p>AFL 的使用有两种，一种是有源码情况，一种是无源码情况。</p>
<p>有源码时，使用过程较为简单，基本步骤如下：</p>
<ol type="1">
<li>使用提供的编译器 wrapper 进行编译 （ <code>afl-gcc</code>）</li>
<li>使用 <code>afl-fuzz</code>，指定一个目录为工作目录，指定初始样本，开始 fuzz。</li>
</ol>
<p>无源码时的使用过程：</p>
<ol type="1">
<li>编译 afl 自己的 qemu</li>
<li>使用 <code>afl-fuzz</code> 开始 fuzz，指定 QEMU 模式。</li>
</ol>
<p>下面我们来具体看看其实现过程。</p>
<h3 id="afl-gcc">afl-gcc</h3>
<p>程序位于 <code>afl-gcc.c</code> 中，其主要功能是作为一个 wrapper 启动对 gcc 的调用。其基本目的是为使用 gcc 进行编译的程序加入 afl 自己的插桩。</p>
<p>gcc 本身的编译存在几个过程，第一个部分是生成汇编，也就是 gcc 本身的功能，之后 gcc 会调用默认的 as，也就是汇编器，由汇编器来生成可执行文件。而 <code>afl-gcc</code> 的目的就是代替 gcc ，而实现过程则是将传入参数传到 gcc 中，并且启动 gcc 进行编译，不过其通过参数调整，将 afl 自己的 as （汇编器）作为默认汇编器，这样就可以在生成汇编之后对汇编进行修改，从而实现 instrumentation 过程。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 这一部分位于 edit_params 中</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 调用的程序是 g++ 或者 gcc 或者 gcj</span></span><br><span class="line">   <span class="keyword">if</span> (!<span class="built_in">strcmp</span>(name, <span class="string">"afl-g++"</span>)) &#123;</span><br><span class="line">      u8* alt_cxx = getenv(<span class="string">"AFL_CXX"</span>);</span><br><span class="line">      cc_params[<span class="number">0</span>] = alt_cxx ? alt_cxx : (u8*)<span class="string">"g++"</span>;</span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (!<span class="built_in">strcmp</span>(name, <span class="string">"afl-gcj"</span>)) &#123;</span><br><span class="line">      u8* alt_cc = getenv(<span class="string">"AFL_GCJ"</span>);</span><br><span class="line">      cc_params[<span class="number">0</span>] = alt_cc ? alt_cc : (u8*)<span class="string">"gcj"</span>;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      u8* alt_cc = getenv(<span class="string">"AFL_CC"</span>);</span><br><span class="line">      cc_params[<span class="number">0</span>] = alt_cc ? alt_cc : (u8*)<span class="string">"gcc"</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// ...</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 循环处理传入 afl-gcc 的参数</span></span><br><span class="line">  <span class="keyword">while</span> (--argc) &#123;</span><br><span class="line">    u8* cur = *(++argv);</span><br><span class="line"></span><br><span class="line"><span class="comment">// -B 用来输入默认的 as 所在目录，所以这里需要覆盖掉</span></span><br><span class="line">    <span class="keyword">if</span> (!<span class="built_in">strncmp</span>(cur, <span class="string">"-B"</span>, <span class="number">2</span>)) &#123;</span><br><span class="line"></span><br><span class="line">      <span class="keyword">if</span> (!be_quiet) WARNF(<span class="string">"-B is already set, overriding"</span>);</span><br><span class="line"></span><br><span class="line">      <span class="keyword">if</span> (!cur[<span class="number">2</span>] &amp;&amp; argc &gt; <span class="number">1</span>) &#123; argc--; argv++; &#125;</span><br><span class="line">      <span class="keyword">continue</span>;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 同时也覆盖掉 integrated-as ，这样才可以使用自定义的 as</span></span><br><span class="line">    <span class="keyword">if</span> (!<span class="built_in">strcmp</span>(cur, <span class="string">"-integrated-as"</span>)) <span class="keyword">continue</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (!<span class="built_in">strcmp</span>(cur, <span class="string">"-pipe"</span>)) <span class="keyword">continue</span>;</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> defined(__FreeBSD__) &amp;&amp; defined(__x86_64__)</span></span><br><span class="line">    <span class="keyword">if</span> (!<span class="built_in">strcmp</span>(cur, <span class="string">"-m32"</span>)) m32_set = <span class="number">1</span>;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (!<span class="built_in">strcmp</span>(cur, <span class="string">"-fsanitize=address"</span>) ||</span><br><span class="line">        !<span class="built_in">strcmp</span>(cur, <span class="string">"-fsanitize=memory"</span>)) asan_set = <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (<span class="built_in">strstr</span>(cur, <span class="string">"FORTIFY_SOURCE"</span>)) fortify_set = <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line">    cc_params[cc_par_cnt++] = cur;</span><br><span class="line"></span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 将 afl 自己的 as 所在目录传入参数</span></span><br><span class="line">  cc_params[cc_par_cnt++] = <span class="string">"-B"</span>;</span><br><span class="line">  cc_params[cc_par_cnt++] = as_path;</span><br></pre></td></tr></table></figure>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="comment">// main 中</span></span><br><span class="line"><span class="comment">// 定位自己的 as</span></span><br><span class="line">  find_as(argv[<span class="number">0</span>]);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 修改传入参数</span></span><br><span class="line">  edit_params(argc, argv);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 启动 gcc</span></span><br><span class="line">  execvp(cc_params[<span class="number">0</span>], (<span class="keyword">char</span>**)cc_params);</span><br><span class="line"></span><br><span class="line">  FATAL(<span class="string">"Oops, failed to execute '%s' - check your PATH"</span>, cc_params[<span class="number">0</span>]);</span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> <span class="number">0</span>;</span><br></pre></td></tr></table></figure>
<h3 id="afl-as">afl-as</h3>
<p>既然 afl-gcc 是通过调用自己的 as 来实现 instrumentation 的，我们就来关注一下其汇编器是如何具体进行 instrumentation 工作的。</p>
<p>汇编器分为两个部分，<code>afl-as.h</code> 和 <code>afl-as.c</code> ，头文件中主要是一些常量的定义，其中包含了插入的汇编内容，.c 文件和之前的 afl-gcc 类似，也是一个 wrapper，最终依然会调用系统的 as 来完成工作，不过在此之前对汇编进行了一些操作，从而完成了 instrumentation。</p>
<p>在这里，其实共享内存已经建立好，共享内存就是一段内存，这一段内存用来保存关于控制流的信息。</p>
<p>我们首先来看 instrumentation 的具体过程：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line">rand_seed = tv.tv_sec ^ tv.tv_usec ^ getpid();</span><br><span class="line"></span><br><span class="line">srandom(rand_seed);</span><br><span class="line"></span><br><span class="line">edit_params(argc, argv); <span class="comment">// 调整参数，同 afl-gcc</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (inst_ratio_str) &#123;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">if</span> (<span class="built_in">sscanf</span>(inst_ratio_str, <span class="string">"%u"</span>, &amp;inst_ratio) != <span class="number">1</span> || inst_ratio &gt; <span class="number">100</span>) </span><br><span class="line">    FATAL(<span class="string">"Bad value of AFL_INST_RATIO (must be between 0 and 100)"</span>);</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (getenv(AS_LOOP_ENV_VAR))</span><br><span class="line">  FATAL(<span class="string">"Endless loop when calling 'as' (remove '.' from your PATH)"</span>);</span><br><span class="line"></span><br><span class="line">setenv(AS_LOOP_ENV_VAR, <span class="string">"1"</span>, <span class="number">1</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">/* When compiling with ASAN, we don't have a particularly elegant way to skip</span></span><br><span class="line"><span class="comment">   ASAN-specific branches. But we can probabilistically compensate for</span></span><br><span class="line"><span class="comment">   that... */</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (getenv(<span class="string">"AFL_USE_ASAN"</span>) || getenv(<span class="string">"AFL_USE_MSAN"</span>)) &#123;</span><br><span class="line">  sanitizer = <span class="number">1</span>;</span><br><span class="line">  inst_ratio /= <span class="number">3</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (!just_version) add_instrumentation(); <span class="comment">// 进行 instrumentation</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (!(pid = fork())) &#123;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 启动真实汇编器</span></span><br><span class="line">  execvp(as_params[<span class="number">0</span>], (<span class="keyword">char</span>**)as_params);</span><br><span class="line">  FATAL(<span class="string">"Oops, failed to execute '%s' - check your PATH"</span>, as_params[<span class="number">0</span>]);</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>核心主要位于 <code>add_instrumentation</code> 中：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> <span class="title">add_instrumentation</span><span class="params">(<span class="keyword">void</span>)</span> </span>&#123;</span><br><span class="line"></span><br><span class="line"><span class="comment">// ...</span></span><br><span class="line"></span><br><span class="line">  <span class="comment">// 打开汇编文件</span></span><br><span class="line">  <span class="keyword">if</span> (input_file) &#123;</span><br><span class="line"></span><br><span class="line">    inf = fopen(input_file, <span class="string">"r"</span>);</span><br><span class="line">    <span class="keyword">if</span> (!inf) PFATAL(<span class="string">"Unable to read '%s'"</span>, input_file);</span><br><span class="line"></span><br><span class="line">  &#125; <span class="keyword">else</span> inf = <span class="built_in">stdin</span>;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 打开用来输出的文件</span></span><br><span class="line">  outfd = open(modified_file, O_WRONLY | O_EXCL | O_CREAT, <span class="number">0600</span>);</span><br><span class="line"></span><br><span class="line">  <span class="keyword">if</span> (outfd &lt; <span class="number">0</span>) PFATAL(<span class="string">"Unable to write to '%s'"</span>, modified_file);</span><br><span class="line"></span><br><span class="line">  outf = fdopen(outfd, <span class="string">"w"</span>);</span><br><span class="line"></span><br><span class="line">  <span class="keyword">if</span> (!outf) PFATAL(<span class="string">"fdopen() failed"</span>);  </span><br><span class="line"></span><br><span class="line">  <span class="comment">// 读取每一行</span></span><br><span class="line">  <span class="keyword">while</span> (fgets(line, MAX_LINE, inf)) &#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* In some cases, we want to defer writing the instrumentation trampoline</span></span><br><span class="line"><span class="comment">       until after all the labels, macros, comments, etc. If we're in this</span></span><br><span class="line"><span class="comment">       mode, and if the line starts with a tab followed by a character, dump</span></span><br><span class="line"><span class="comment">       the trampoline now. */</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// 特殊情况需要延迟写入 instrumentation，则咋你这个时候需要写入 trampoline_fmt_*，</span></span><br><span class="line">    <span class="comment">// 具体根据架构决定写入内容，该部分内容位于头文件中，是一小段汇编代码</span></span><br><span class="line">    <span class="comment">// 其中R(MAP_SIZE) 是生成随机数</span></span><br><span class="line">    <span class="keyword">if</span> (!pass_thru &amp;&amp; !skip_intel &amp;&amp; !skip_app &amp;&amp; !skip_csect &amp;&amp; instr_ok &amp;&amp;</span><br><span class="line">        instrument_next &amp;&amp; line[<span class="number">0</span>] == <span class="string">'\t'</span> &amp;&amp; <span class="built_in">isalpha</span>(line[<span class="number">1</span>])) &#123;</span><br><span class="line"></span><br><span class="line">      <span class="built_in">fprintf</span>(outf, use_64bit ? trampoline_fmt_64 : trampoline_fmt_32,</span><br><span class="line">              R(MAP_SIZE));</span><br><span class="line"></span><br><span class="line">      instrument_next = <span class="number">0</span>;</span><br><span class="line">      ins_lines++;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* Output the actual line, call it a day in pass-thru mode. */</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// 写入原文</span></span><br><span class="line">    <span class="built_in">fputs</span>(line, outf);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (pass_thru) <span class="keyword">continue</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* All right, this is where the actual fun begins. For one, we only want to</span></span><br><span class="line"><span class="comment">       instrument the .text section. So, let's keep track of that in processed</span></span><br><span class="line"><span class="comment">       files - and let's set instr_ok accordingly. */</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// 进行跳转统计的 instrumentation</span></span><br><span class="line">    <span class="comment">// 确认只处理 .text 段的内容</span></span><br><span class="line">    <span class="keyword">if</span> (line[<span class="number">0</span>] == <span class="string">'\t'</span> &amp;&amp; line[<span class="number">1</span>] == <span class="string">'.'</span>) &#123;</span><br><span class="line"></span><br><span class="line">      <span class="comment">/* OpenBSD puts jump tables directly inline with the code, which is</span></span><br><span class="line"><span class="comment">         a bit annoying. They use a specific format of p2align directives</span></span><br><span class="line"><span class="comment">         around them, so we use that as a signal. */</span></span><br><span class="line"></span><br><span class="line">      <span class="keyword">if</span> (!clang_mode &amp;&amp; instr_ok &amp;&amp; !<span class="built_in">strncmp</span>(line + <span class="number">2</span>, <span class="string">"p2align "</span>, <span class="number">8</span>) &amp;&amp;</span><br><span class="line">          <span class="built_in">isdigit</span>(line[<span class="number">10</span>]) &amp;&amp; line[<span class="number">11</span>] == <span class="string">'\n'</span>) skip_next_label = <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line">      <span class="keyword">if</span> (!<span class="built_in">strncmp</span>(line + <span class="number">2</span>, <span class="string">"text\n"</span>, <span class="number">5</span>) ||</span><br><span class="line">          !<span class="built_in">strncmp</span>(line + <span class="number">2</span>, <span class="string">"section\t.text"</span>, <span class="number">13</span>) ||</span><br><span class="line">          !<span class="built_in">strncmp</span>(line + <span class="number">2</span>, <span class="string">"section\t__TEXT,__text"</span>, <span class="number">21</span>) ||</span><br><span class="line">          !<span class="built_in">strncmp</span>(line + <span class="number">2</span>, <span class="string">"section __TEXT,__text"</span>, <span class="number">21</span>)) &#123;</span><br><span class="line">        instr_ok = <span class="number">1</span>;</span><br><span class="line">        <span class="keyword">continue</span>; </span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">      <span class="keyword">if</span> (!<span class="built_in">strncmp</span>(line + <span class="number">2</span>, <span class="string">"section\t"</span>, <span class="number">8</span>) ||</span><br><span class="line">          !<span class="built_in">strncmp</span>(line + <span class="number">2</span>, <span class="string">"section "</span>, <span class="number">8</span>) ||</span><br><span class="line">          !<span class="built_in">strncmp</span>(line + <span class="number">2</span>, <span class="string">"bss\n"</span>, <span class="number">4</span>) ||</span><br><span class="line">          !<span class="built_in">strncmp</span>(line + <span class="number">2</span>, <span class="string">"data\n"</span>, <span class="number">5</span>)) &#123;</span><br><span class="line">        instr_ok = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">continue</span>;</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* Detect off-flavor assembly (rare, happens in gdb). When this is</span></span><br><span class="line"><span class="comment">       encountered, we set skip_csect until the opposite directive is</span></span><br><span class="line"><span class="comment">       seen, and we do not instrument. */</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (<span class="built_in">strstr</span>(line, <span class="string">".code"</span>)) &#123;</span><br><span class="line"></span><br><span class="line">      <span class="keyword">if</span> (<span class="built_in">strstr</span>(line, <span class="string">".code32"</span>)) skip_csect = use_64bit;</span><br><span class="line">      <span class="keyword">if</span> (<span class="built_in">strstr</span>(line, <span class="string">".code64"</span>)) skip_csect = !use_64bit;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// ...</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// 需要加入跳转统计的地方：</span></span><br><span class="line">    <span class="comment">// main 函数</span></span><br><span class="line">    <span class="comment">// .L0 是 gcc 生成的汇编中，跳转目标的 label</span></span><br><span class="line">    <span class="comment">// .LBB0_0 clang 的跳转目标 label</span></span><br><span class="line">    <span class="comment">// \tjXX 但不是 jmp，即所有条件跳转</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">/* If we're in the right mood for instrumenting, check for function</span></span><br><span class="line"><span class="comment">       names or conditional labels. This is a bit messy, but in essence,</span></span><br><span class="line"><span class="comment">       we want to catch:</span></span><br><span class="line"><span class="comment">         ^main:      - function entry point (always instrumented)</span></span><br><span class="line"><span class="comment">         ^.L0:       - GCC branch label</span></span><br><span class="line"><span class="comment">         ^.LBB0_0:   - clang branch label (but only in clang mode)</span></span><br><span class="line"><span class="comment">         ^\tjnz foo  - conditional branches</span></span><br><span class="line"><span class="comment">       ...but not:</span></span><br><span class="line"><span class="comment">         ^# BB#0:    - clang comments</span></span><br><span class="line"><span class="comment">         ^ # BB#0:   - ditto</span></span><br><span class="line"><span class="comment">         ^.Ltmp0:    - clang non-branch labels</span></span><br><span class="line"><span class="comment">         ^.LC0       - GCC non-branch labels</span></span><br><span class="line"><span class="comment">         ^.LBB0_0:   - ditto (when in GCC mode)</span></span><br><span class="line"><span class="comment">         ^\tjmp foo  - non-conditional jumps</span></span><br><span class="line"><span class="comment">       Additionally, clang and GCC on MacOS X follow a different convention</span></span><br><span class="line"><span class="comment">       with no leading dots on labels, hence the weird maze of #ifdefs</span></span><br><span class="line"><span class="comment">       later on.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (skip_intel || skip_app || skip_csect || !instr_ok ||</span><br><span class="line">        line[<span class="number">0</span>] == <span class="string">'#'</span> || line[<span class="number">0</span>] == <span class="string">' '</span>) <span class="keyword">continue</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* Conditional branch instruction (jnz, etc). We append the instrumentation</span></span><br><span class="line"><span class="comment">       right after the branch (to instrument the not-taken path) and at the</span></span><br><span class="line"><span class="comment">       branch destination label (handled later on). */</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (line[<span class="number">0</span>] == <span class="string">'\t'</span>) &#123;</span><br><span class="line"></span><br><span class="line">      <span class="comment">// 条件跳转，加入trampoline</span></span><br><span class="line">      <span class="keyword">if</span> (line[<span class="number">1</span>] == <span class="string">'j'</span> &amp;&amp; line[<span class="number">2</span>] != <span class="string">'m'</span> &amp;&amp; R(<span class="number">100</span>) &lt; inst_ratio) &#123;</span><br><span class="line"></span><br><span class="line">        <span class="built_in">fprintf</span>(outf, use_64bit ? trampoline_fmt_64 : trampoline_fmt_32,</span><br><span class="line">                R(MAP_SIZE));</span><br><span class="line"></span><br><span class="line">        ins_lines++;</span><br><span class="line"></span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">      <span class="keyword">continue</span>;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// ...</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">if</span> (ins_lines)</span><br><span class="line">    <span class="built_in">fputs</span>(use_64bit ? main_payload_64 : main_payload_32, outf);</span><br><span class="line"></span><br><span class="line">  <span class="keyword">if</span> (input_file) fclose(inf);</span><br><span class="line">  fclose(outf);</span><br><span class="line"></span><br><span class="line">  <span class="comment">// ...</span></span><br></pre></td></tr></table></figure>
<p>R 的定义位于 <code>types.h</code> 中：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">ifdef</span> AFL_LLVM_PASS</span></span><br><span class="line"><span class="meta">#  <span class="meta-keyword">define</span> AFL_R(x) (random() % (x))</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">else</span></span></span><br><span class="line"><span class="meta">#  <span class="meta-keyword">define</span> R(x) (random() % (x)) <span class="comment">// 生成随机数，保证在 x 范围内，也就是共享内存大小内</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span> <span class="comment">/* ^AFL_LLVM_PASS */</span></span></span><br></pre></td></tr></table></figure>
<p>大体来讲，就是在需要加入跳转统计的地方加入 trampoline 。</p>
<p>下面大概来看看 trampoline 在做什么：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">const</span> u8* trampoline_fmt_64 =</span><br><span class="line"></span><br><span class="line">  <span class="string">"\n"</span></span><br><span class="line">  <span class="string">"/* --- AFL TRAMPOLINE (64-BIT) --- */\n"</span></span><br><span class="line">  <span class="string">"\n"</span></span><br><span class="line">  <span class="string">".align 4\n"</span></span><br><span class="line">  <span class="string">"\n"</span></span><br><span class="line">  <span class="string">"leaq -(128+24)(%%rsp), %%rsp\n"</span> <span class="comment">// 保存插桩用到的寄存器内容</span></span><br><span class="line">  <span class="string">"movq %%rdx,  0(%%rsp)\n"</span></span><br><span class="line">  <span class="string">"movq %%rcx,  8(%%rsp)\n"</span></span><br><span class="line">  <span class="string">"movq %%rax, 16(%%rsp)\n"</span></span><br><span class="line">  <span class="string">"movq $0x%08x, %%rcx\n"</span> <span class="comment">// rcx 中存放了一个随机数，即使用 R 宏生成的随机数</span></span><br><span class="line">  <span class="string">"call __afl_maybe_log\n"</span></span><br><span class="line">  <span class="string">"movq 16(%%rsp), %%rax\n"</span> <span class="comment">// 恢复寄存器</span></span><br><span class="line">  <span class="string">"movq  8(%%rsp), %%rcx\n"</span></span><br><span class="line">  <span class="string">"movq  0(%%rsp), %%rdx\n"</span></span><br><span class="line">  <span class="string">"leaq (128+24)(%%rsp), %%rsp\n"</span></span><br><span class="line">  <span class="string">"\n"</span></span><br><span class="line">  <span class="string">"/* --- END --- */\n"</span></span><br><span class="line">  <span class="string">"\n"</span>;</span><br></pre></td></tr></table></figure>
<p>其实这里的随机数用来唯一标识了这一个跳转。</p>
<p>在 __afl_maybe_log 中：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">const</span> u8* main_payload_64 = </span><br><span class="line"></span><br><span class="line">  <span class="string">"\n"</span></span><br><span class="line">  <span class="string">"/* --- AFL MAIN PAYLOAD (64-BIT) --- */\n"</span></span><br><span class="line">  <span class="string">"\n"</span></span><br><span class="line">  <span class="string">".text\n"</span></span><br><span class="line">  <span class="string">".att_syntax\n"</span></span><br><span class="line">  <span class="string">".code64\n"</span></span><br><span class="line">  <span class="string">".align 8\n"</span></span><br><span class="line">  <span class="string">"\n"</span></span><br><span class="line">  <span class="string">"__afl_maybe_log:\n"</span></span><br><span class="line">  <span class="string">"\n"</span></span><br><span class="line">#<span class="keyword">if</span> defined(__OpenBSD__)  || (defined(__FreeBSD__) &amp;&amp; (__FreeBSD__ &lt; <span class="number">9</span>))</span><br><span class="line">  <span class="string">"  .byte 0x9f /* lahf */\n"</span></span><br><span class="line">#<span class="keyword">else</span></span><br><span class="line">  <span class="string">"  lahf\n"</span></span><br><span class="line">#endif <span class="comment">/* ^__OpenBSD__, etc */</span></span><br><span class="line">  <span class="string">"  seto  %al\n"</span></span><br><span class="line">  <span class="string">"\n"</span></span><br><span class="line">  <span class="string">"  /* Check if SHM region is already mapped. */\n"</span></span><br><span class="line">  <span class="comment">// 确认共享内存的存在</span></span><br><span class="line">  <span class="string">"\n"</span></span><br><span class="line">  <span class="string">"  movq  __afl_area_ptr(%rip), %rdx\n"</span></span><br><span class="line">  <span class="string">"  testq %rdx, %rdx\n"</span></span><br><span class="line">  <span class="string">"  je    __afl_setup\n"</span></span><br><span class="line">  <span class="string">"\n"</span></span><br><span class="line">  <span class="comment">// 共享内存没有问题，存入控制流信息</span></span><br><span class="line">  <span class="string">"__afl_store:\n"</span></span><br><span class="line">  <span class="string">"\n"</span></span><br><span class="line">  <span class="string">"  /* Calculate and store hit for the code location specified in rcx. */\n"</span></span><br><span class="line">  <span class="string">"\n"</span></span><br><span class="line">#ifndef COVERAGE_ONLY</span><br><span class="line">  <span class="string">"  xorq __afl_prev_loc(%rip), %rcx\n"</span> <span class="comment">// 将跳转过来的位置的随机数与当前随机数 xor</span></span><br><span class="line">  <span class="string">"  xorq %rcx, __afl_prev_loc(%rip)\n"</span></span><br><span class="line">  <span class="string">"  shrq $1, __afl_prev_loc(%rip)\n"</span> <span class="comment">// 右移一位</span></span><br><span class="line">#endif <span class="comment">/* ^!COVERAGE_ONLY */</span></span><br><span class="line">  <span class="string">"\n"</span></span><br><span class="line">#ifdef SKIP_COUNTS</span><br><span class="line">  <span class="string">"  orb  $1, (%rdx, %rcx, 1)\n"</span></span><br><span class="line">#<span class="keyword">else</span></span><br><span class="line">  <span class="string">"  incb (%rdx, %rcx, 1)\n"</span> <span class="comment">// 写入到共享内存中</span></span><br><span class="line">  <span class="comment">// ...</span></span><br></pre></td></tr></table></figure>
<p>可以理解为：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">current = random() % mem_size;</span><br><span class="line">mem[prev ^ current]++;</span><br><span class="line">prev = current &gt;&gt; <span class="number">1</span>;</span><br></pre></td></tr></table></figure>
<p>也就是说，对跳转位置的记录都是用随机数记录的，而控制流表现为一个 bit ，其所在位置是源到目标的随机数的异或值，然后每一次异或将当前位置随机数右移一位进行表示。右移的目的主要是为了区分源和目标，因为 xor 本身是对称的，这样引入了非对称性。</p>
<p>换句话说，这里可以理解为每一个条件跳转（或是插桩位置，更为准确的话）都用一个共享内存大小范围内的一个随机数标识，然后用右移一位表示源（从他走向其他位置），其原值表示目标（从其他位置走到他），最终共享内存相当于表示了一个表，这个表就是对路径的一个总结。</p>
<p>这个表的形式相当于把一条路径两两拆开，比如 <code>A -&gt; B -&gt; C</code> 拆为 <code>(A, B)</code> 和 <code>(B, C)</code>，然后在共享内存里表示这么一个表：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">+-----------+----------+----------+</span><br><span class="line">| 二元路径  | A -&gt; B   |  B -&gt; C  |</span><br><span class="line">+-----------+----------+----------+</span><br><span class="line">|  次数     |          |          |</span><br><span class="line">+-----------+---------------------+</span><br></pre></td></tr></table></figure>
<p>然后这个表（共享内存中），就可以作为判断是否走向新路径的依据，如果表不一样，就认为走到了新的路径，而表中的 <code>-&gt;</code>，就通过 <code>(id(A) &gt;&gt; 1) ^ (id(B))</code> 来实现（以此作为索引）。</p>
<h3 id="qemu-mode">QEMU mode</h3>
<p>我看到的文章似乎都没有介绍 QEMU 是如何进行 instrumentation 的，其实思路接近。</p>
<p>afl 主要使用了 QEMU 的 user mode，在 QEMU 的执行过程中，存在一个翻译过程，其执行流程为逐次翻译基本块，每一次翻译一个基本块，碰到跳转时，找到跳转目标位置，然后将目标位置逐次翻译，直到碰到跳转，将跳转翻译为跳回 QEMU 内容的跳转，这样在下一次执行到该位置的时候，如果碰到跳转，就会进入下一轮翻译。</p>
<p>其实 afl 就是在这个翻译过程中，如果碰到新的块，就加入和 afl-as 一样的内容，进行共享内存赋值，大概内容如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"> <span class="keyword">typedef</span> <span class="class"><span class="keyword">struct</span> <span class="title">SyncClocks</span> &#123;</span></span><br><span class="line">@@ <span class="number">-144</span>,<span class="number">6</span> +<span class="number">146</span>,<span class="number">8</span> @@</span><br><span class="line">     <span class="keyword">int</span> tb_exit;</span><br><span class="line">     <span class="keyword">uint8_t</span> *tb_ptr = itb-&gt;tc_ptr;</span><br><span class="line"> </span><br><span class="line">+    AFL_QEMU_CPU_SNIPPET2;</span><br><span class="line">+</span><br><span class="line">     qemu_log_mask_and_addr(CPU_LOG_EXEC, itb-&gt;pc,</span><br><span class="line">                            <span class="string">"Trace %p [%d: "</span> TARGET_FMT_lx <span class="string">"] %s\n"</span>,</span><br><span class="line">                            itb-&gt;tc_ptr, cpu-&gt;cpu_index, itb-&gt;pc,</span><br><span class="line">@@ <span class="number">-365</span>,<span class="number">6</span> +<span class="number">369</span>,<span class="number">7</span> @@</span><br><span class="line">             <span class="keyword">if</span> (!tb) &#123;</span><br><span class="line">                 <span class="comment">/* if no translated code available, then translate it now */</span></span><br><span class="line">                 tb = tb_gen_code(cpu, pc, cs_base, flags, <span class="number">0</span>);</span><br><span class="line">+                AFL_QEMU_CPU_SNIPPET1;</span><br><span class="line">             &#125;</span><br><span class="line"> </span><br><span class="line">             mmap_unlock();</span><br><span class="line"></span><br><span class="line"><span class="comment">// 其中 两个 SNIPPET 如下</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// 一些功能性的处理，主要是对翻译的一些处理，不用很在意</span></span><br><span class="line">#define AFL_QEMU_CPU_SNIPPET1 <span class="keyword">do</span> &#123; \</span><br><span class="line">    afl_request_tsl(pc, cs_base, flags); \</span><br><span class="line">  &#125; <span class="keyword">while</span> (<span class="number">0</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">/* This snippet kicks in when the instruction pointer is positioned at</span></span><br><span class="line"><span class="comment">   _start and does the usual forkserver stuff, not very different from</span></span><br><span class="line"><span class="comment">   regular instrumentation injected via afl-as.h. */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 和一段是在实际翻译中，因为翻译后就是执行，所以此时可以进行</span></span><br><span class="line"><span class="comment">// afl-as 中 afl_maybe_log 的功能，对控制流进行记录</span></span><br><span class="line">#define AFL_QEMU_CPU_SNIPPET2 <span class="keyword">do</span> &#123; \</span><br><span class="line">    <span class="keyword">if</span>(itb-&gt;pc == afl_entry_point) &#123; \</span><br><span class="line">      afl_setup(); \</span><br><span class="line">      afl_forkserver(cpu); \</span><br><span class="line">    &#125; \</span><br><span class="line">    afl_maybe_log(itb-&gt;pc); \</span><br><span class="line">  &#125; <span class="keyword">while</span> (<span class="number">0</span>)</span><br></pre></td></tr></table></figure>
<h3 id="afl-fuzz">afl-fuzz</h3>
<p>这一部分是 afl fuzz 过程的核心逻辑，其中有几个点需要我们关注，我们将会一个一个来看。</p>
<p>需要解释的内容包括如下几个部分：</p>
<ul>
<li>forkserver：用来加速程序启动过程</li>
<li>如何使用共享内存中的控制流信息</li>
</ul>
<p>其实还有关于变异的部分，但是变异的部分本身对于使用价值一般，我这里暂时没有关注。</p>
<p>第一个部分是 forkserver。</p>
<p>forkserver 本身思想很简单，在 afl fuzz 的过程中需要启动目标程序很多次，然而程序的启动过程本身是比较复杂的，很多初始化工作需要完成，那我们可以在程序初始化完成后启动一个 server，在 server 中等到消息，如果有消息来临，我们就 fork 一段新程序，这个时候 fork 出来的新程序是已经初始化后的，所以此时就可以节约很多初始化工作。</p>
<p>在 afl-fuzz 对 forkserver 进行初始化的时候，会 fork 出一个新的进程，这个进程就是 forkserver 进程，这个进程和主进程通过管道进行通信。而真正的 forkserver 其实位于进程内，是在插桩的时候放入的，位于 main_payload 中，在之前的 afl-as 解析中我忽略了这一部分，这里拿出来一起看会更加容易。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="comment">// 建立通信管道</span></span><br><span class="line"><span class="keyword">if</span> (pipe(st_pipe) || pipe(ctl_pipe)) PFATAL(<span class="string">"pipe() failed"</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// fork 出 forkserver 的进程</span></span><br><span class="line">forksrv_pid = fork();</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (forksrv_pid &lt; <span class="number">0</span>) PFATAL(<span class="string">"fork() failed"</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (!forksrv_pid) &#123;</span><br><span class="line"></span><br><span class="line">   <span class="comment">// ... 初始化 forkserver</span></span><br><span class="line"></span><br><span class="line">  <span class="class"><span class="keyword">struct</span> <span class="title">rlimit</span> <span class="title">r</span>;</span></span><br><span class="line"></span><br><span class="line">  <span class="comment">/* Umpf. On OpenBSD, the default fd limit for root users is set to</span></span><br><span class="line"><span class="comment">     soft 128. Let's try to fix that... */</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">if</span> (!getrlimit(RLIMIT_NOFILE, &amp;r) &amp;&amp; r.rlim_cur &lt; FORKSRV_FD + <span class="number">2</span>) &#123;</span><br><span class="line"></span><br><span class="line">    r.rlim_cur = FORKSRV_FD + <span class="number">2</span>;</span><br><span class="line">    setrlimit(RLIMIT_NOFILE, &amp;r); <span class="comment">/* Ignore errors */</span></span><br><span class="line"></span><br><span class="line">  &#125;</span><br></pre></td></tr></table></figure>
<p>在 afl-as 中，也就是插入到目标进程内的地方。</p>
<p>这一部分是汇编编写，阅读起来比较麻烦，大致上就是通过管道进行通讯，获取到信息之后就进行 fork。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">"__afl_forkserver:\n"</span></span><br><span class="line"><span class="string">"\n"</span></span><br><span class="line"><span class="string">"  /* Enter the fork server mode to avoid the overhead of execve() calls. */\n"</span></span><br><span class="line"><span class="string">"\n"</span></span><br><span class="line"><span class="string">"  pushl %eax\n"</span></span><br><span class="line"><span class="string">"  pushl %ecx\n"</span></span><br><span class="line"><span class="string">"  pushl %edx\n"</span></span><br><span class="line"><span class="string">"\n"</span></span><br><span class="line"><span class="string">"  /* Phone home and tell the parent that we're OK. (Note that signals with\n"</span></span><br><span class="line"><span class="string">"     no SA_RESTART will mess it up). If this fails, assume that the fd is\n"</span></span><br><span class="line"><span class="string">"     closed because we were execve()d from an instrumented binary, or because\n"</span> </span><br><span class="line"><span class="string">"     the parent doesn't want to use the fork server. */\n"</span></span><br><span class="line"><span class="string">"\n"</span></span><br><span class="line"><span class="string">"  pushl $4          /* length    */\n"</span></span><br><span class="line"><span class="string">"  pushl $__afl_temp /* data      */\n"</span></span><br><span class="line"><span class="string">"  pushl $"</span> STRINGIFY((FORKSRV_FD + <span class="number">1</span>)) <span class="string">"  /* file desc */\n"</span></span><br><span class="line"><span class="string">"  call  write\n"</span> <span class="comment">// hello 信息，确认 forkserver 成功进入</span></span><br><span class="line"><span class="string">"  addl  $12, %esp\n"</span></span><br><span class="line"><span class="string">"\n"</span></span><br><span class="line"><span class="string">"  cmpl  $4, %eax\n"</span></span><br><span class="line"><span class="string">"  jne   __afl_fork_resume\n"</span></span><br><span class="line"><span class="string">"\n"</span></span><br><span class="line"><span class="string">"__afl_fork_wait_loop:\n"</span></span><br><span class="line"><span class="string">"\n"</span></span><br><span class="line"><span class="string">"  /* Wait for parent by reading from the pipe. Abort if read fails. */\n"</span></span><br><span class="line"><span class="string">"\n"</span></span><br><span class="line"><span class="string">"  pushl $4          /* length    */\n"</span></span><br><span class="line"><span class="string">"  pushl $__afl_temp /* data      */\n"</span></span><br><span class="line"><span class="string">"  pushl $"</span> STRINGIFY(FORKSRV_FD) <span class="string">"        /* file desc */\n"</span></span><br><span class="line"><span class="string">"  call  read\n"</span> <span class="comment">// 等待消息</span></span><br><span class="line"><span class="string">"  addl  $12, %esp\n"</span></span><br><span class="line"><span class="string">"\n"</span></span><br><span class="line"><span class="string">"  cmpl  $4, %eax\n"</span></span><br><span class="line"><span class="string">"  jne   __afl_die\n"</span></span><br><span class="line"><span class="string">"\n"</span></span><br><span class="line"><span class="string">"  /* Once woken up, create a clone of our process. This is an excellent use\n"</span></span><br><span class="line"><span class="string">"     case for syscall(__NR_clone, 0, CLONE_PARENT), but glibc boneheadedly\n"</span></span><br><span class="line"><span class="string">"     caches getpid() results and offers no way to update the value, breaking\n"</span></span><br><span class="line"><span class="string">"     abort(), raise(), and a bunch of other things :-( */\n"</span></span><br><span class="line"><span class="string">"\n"</span></span><br><span class="line"><span class="string">"  call fork\n"</span> <span class="comment">// 进行 fork，这样就不再需要 afl-fuzz 进行很多次 execve，而是在一个目标程序里进行 fork，减少 execve 加载 ELF 文件等操作带来的 overhead</span></span><br><span class="line"><span class="string">"\n"</span></span><br><span class="line"><span class="string">"  cmpl $0, %eax\n"</span></span><br><span class="line"><span class="string">"  jl   __afl_die\n"</span></span><br><span class="line"><span class="string">"  je   __afl_fork_resume\n"</span></span><br><span class="line"><span class="string">"\n"</span></span><br><span class="line"><span class="string">"  /* In parent process: write PID to pipe, then wait for child. */\n"</span></span><br><span class="line"><span class="string">"\n"</span></span><br><span class="line"><span class="string">"  movl  %eax, __afl_fork_pid\n"</span></span><br><span class="line"><span class="string">"\n"</span></span><br><span class="line"><span class="string">"  pushl $4              /* length    */\n"</span></span><br><span class="line"><span class="string">"  pushl $__afl_fork_pid /* data      */\n"</span></span><br><span class="line"><span class="string">"  pushl $"</span> STRINGIFY((FORKSRV_FD + <span class="number">1</span>)) <span class="string">"      /* file desc */\n"</span></span><br><span class="line"><span class="string">"  call  write\n"</span></span><br><span class="line"><span class="string">"  addl  $12, %esp\n"</span></span><br><span class="line"><span class="string">"\n"</span></span><br><span class="line"><span class="string">"  pushl $0             /* no flags  */\n"</span></span><br><span class="line"><span class="string">"  pushl $__afl_temp    /* status    */\n"</span></span><br><span class="line"><span class="string">"  pushl __afl_fork_pid /* PID       */\n"</span></span><br><span class="line"><span class="string">"  call  waitpid\n"</span></span><br><span class="line"><span class="string">"  addl  $12, %esp\n"</span></span><br><span class="line"><span class="string">"\n"</span></span><br><span class="line"><span class="string">"  cmpl  $0, %eax\n"</span></span><br><span class="line"><span class="string">"  jle   __afl_die\n"</span></span><br><span class="line"><span class="string">"\n"</span></span><br><span class="line"><span class="string">"  /* Relay wait status to pipe, then loop back. */\n"</span></span><br><span class="line"><span class="string">"\n"</span></span><br><span class="line"><span class="string">"  pushl $4          /* length    */\n"</span></span><br><span class="line"><span class="string">"  pushl $__afl_temp /* data      */\n"</span></span><br><span class="line"><span class="string">"  pushl $"</span> STRINGIFY((FORKSRV_FD + <span class="number">1</span>)) <span class="string">"  /* file desc */\n"</span></span><br><span class="line"><span class="string">"  call  write\n"</span></span><br><span class="line"><span class="string">"  addl  $12, %esp\n"</span></span><br><span class="line"><span class="string">"\n"</span></span><br><span class="line"><span class="string">"  jmp __afl_fork_wait_loop\n"</span></span><br><span class="line"><span class="string">"\n"</span></span><br><span class="line"><span class="string">"__afl_fork_resume:\n"</span></span><br><span class="line"><span class="string">"\n"</span></span><br><span class="line"><span class="string">"  /* In child process: close fds, resume execution. */\n"</span></span><br><span class="line"><span class="string">"\n"</span></span><br><span class="line"><span class="string">"  pushl $"</span> STRINGIFY(FORKSRV_FD) <span class="string">"\n"</span></span><br><span class="line"><span class="string">"  call  close\n"</span></span><br><span class="line"><span class="string">"\n"</span></span><br><span class="line"><span class="string">"  pushl $"</span> STRINGIFY((FORKSRV_FD + <span class="number">1</span>)) <span class="string">"\n"</span></span><br><span class="line"><span class="string">"  call  close\n"</span></span><br><span class="line"><span class="string">"\n"</span></span><br><span class="line"><span class="string">"  addl  $8, %esp\n"</span></span><br><span class="line"><span class="string">"\n"</span></span><br><span class="line"><span class="string">"  popl %edx\n"</span></span><br><span class="line"><span class="string">"  popl %ecx\n"</span></span><br><span class="line"><span class="string">"  popl %eax\n"</span></span><br><span class="line"><span class="string">"  jmp  __afl_store\n"</span></span><br><span class="line"><span class="string">"\n"</span></span><br></pre></td></tr></table></figure>
<p>第二部分，关于如何使用内存中的控制流信息。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 通过共享内存，来得到一个 hash 值</span></span><br><span class="line">   cksum = hash32(trace_bits, MAP_SIZE, HASH_CONST);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 如果 hash 存在不同，说明和之前的执行流程有变</span></span><br><span class="line"><span class="comment">// 这里得到变动的位置，方便在后续中标出该用例导致了变动（variable）</span></span><br><span class="line">    <span class="keyword">if</span> (q-&gt;exec_cksum != cksum) &#123;</span><br><span class="line"></span><br><span class="line">      u8 hnb = has_new_bits(virgin_bits);</span><br><span class="line">      <span class="keyword">if</span> (hnb &gt; new_bits) new_bits = hnb;</span><br><span class="line"></span><br><span class="line">      <span class="keyword">if</span> (q-&gt;exec_cksum) &#123;</span><br><span class="line"></span><br><span class="line">        u32 i;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; MAP_SIZE; i++) &#123;</span><br><span class="line"></span><br><span class="line">          <span class="keyword">if</span> (!var_bytes[i] &amp;&amp; first_trace[i] != trace_bits[i]) &#123;</span><br><span class="line"></span><br><span class="line">            var_bytes[i] = <span class="number">1</span>;</span><br><span class="line">            stage_max    = CAL_CYCLES_LONG;</span><br><span class="line"></span><br><span class="line">          &#125;</span><br><span class="line"></span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        var_detected = <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line">      &#125; <span class="keyword">else</span> &#123;</span><br><span class="line"></span><br><span class="line">        q-&gt;exec_cksum = cksum;</span><br><span class="line">        <span class="built_in">memcpy</span>(first_trace, trace_bits, MAP_SIZE);</span><br><span class="line"></span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  stop_us = get_cur_time_us();</span><br><span class="line"></span><br><span class="line">  total_cal_us     += stop_us - start_us;</span><br><span class="line">  total_cal_cycles += stage_max;</span><br><span class="line"></span><br><span class="line">  <span class="comment">/* OK, let's collect some stats about the performance of this test case.</span></span><br><span class="line"><span class="comment">     This is used for fuzzing air time calculations in calculate_score(). */</span></span><br><span class="line"></span><br><span class="line">  q-&gt;exec_us     = (stop_us - start_us) / stage_max;</span><br><span class="line">  q-&gt;bitmap_size = count_bytes(trace_bits);</span><br><span class="line">  q-&gt;handicap    = handicap;</span><br><span class="line">  q-&gt;cal_failed  = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">  total_bitmap_size += q-&gt;bitmap_size;</span><br><span class="line">  total_bitmap_entries++;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 对该用例评分，在之后选择中会按照该评分作为用例的优先级</span></span><br><span class="line">  update_bitmap_score(q);</span><br><span class="line"></span><br><span class="line">  <span class="comment">/* If this case didn't result in new output from the instrumentation, tell</span></span><br><span class="line"><span class="comment">     parent. This is a non-critical problem, but something to warn the user</span></span><br><span class="line"><span class="comment">     about. */</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">if</span> (!dumb_mode &amp;&amp; first_run &amp;&amp; !fault &amp;&amp; !new_bits) fault = FAULT_NOBITS;</span><br><span class="line"></span><br><span class="line">abort_calibration:</span><br><span class="line"></span><br><span class="line">  <span class="keyword">if</span> (new_bits == <span class="number">2</span> &amp;&amp; !q-&gt;has_new_cov) &#123;</span><br><span class="line">    q-&gt;has_new_cov = <span class="number">1</span>;</span><br><span class="line">    queued_with_cov++;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">/* Mark variable paths. */</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">if</span> (var_detected) &#123;</span><br><span class="line"></span><br><span class="line">    var_byte_count = count_bytes(var_bytes);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (!q-&gt;var_behavior) &#123;</span><br><span class="line">      mark_as_variable(q);</span><br><span class="line">      queued_variable++;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>
<h2 id="总结">总结</h2>
<p>这部分内容主要是对 AFL 的大致思路和实现的部分细节做了一些解释，在理解 AFL 上有一定帮助。但是事实上 AFL 的使用还有很多地方需要考虑，不仅仅是了解思路和细节，还需要操作目标程序，找准 fuzz 的点，这些都很重要，之后我也会注重这一方面的学习了解。</p>

    </div>
    
    <div class="post-footer">
        <div>
            
            转载声明：
            商业转载请联系作者获得授权,非商业转载请注明出处 © <a href="" target="_blank">Snippet</a>
            
            
        </div>
        <div>
            
        </div>
    </div>
</article>
<div class="article-nav prev-next-wrap clearfix">
    
    <a href="/2019/11/05/shallow-talks-on-fp/" class="pre-post btn btn-default" title='浅谈函数式编程（1）'>
        <i class="fa fa-angle-left fa-fw"></i><span class="hidden-lg">上一篇</span>
        <span class="hidden-xs">
            浅谈函数式编程（1）</span>
    </a>
    
    
    <a href="/2019/09/19/learning/" class="next-post btn btn-default" title='目前学习计划'>
        <span class="hidden-lg">下一篇</span>
        <span class="hidden-xs">
            目前学习计划</span><i class="fa fa-angle-right fa-fw"></i>
    </a>
    
</div>

<div id="comments">
    

<div id="vcomments" class="valine"></div>
<!--<script src="//cdn1.lncld.net/static/js/3.0.4/av-min.js"></script>
<script src="/assets/valine.min.js"></script>-->
<script src="//cdn1.lncld.net/static/js/3.0.4/av-min.js"></script>
<script src="//unpkg.com/valine@latest/dist/Valine.min.js"></script>
<script>
new Valine({
    av: AV,
    el: '#vcomments',
    appId: 'sBJ8fsglfz3e3AeXQbE8d8H8-gzGzoHsz',
    appKey: 'WFXH17M73py6bGqWl0ffMbHG',
    placeholder: '说点什么吧',
    notify: false,
    verify: true,
    avatar: 'mm',
    meta: 'nick,mail'.split(','),
    pageSize: '10',
    path: window.location.pathname,
    lang: 'zh-CN'.toLowerCase()
})
</script>



</div>


                </main>
                
                    <aside id="article-toc" role="navigation" class="col-md-4">
    <div class="widget">
        <h3 class="title">
            文章目录
        </h3>
        
        <ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#afl-浅读"><span class="toc-text">AFL 浅读</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#afl-基本思路"><span class="toc-text">AFL 基本思路</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#afl-大致流程"><span class="toc-text">AFL 大致流程</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#一些细节"><span class="toc-text">一些细节</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#使用过程"><span class="toc-text">使用过程</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#afl-gcc"><span class="toc-text">afl-gcc</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#afl-as"><span class="toc-text">afl-as</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#qemu-mode"><span class="toc-text">QEMU mode</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#afl-fuzz"><span class="toc-text">afl-fuzz</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#总结"><span class="toc-text">总结</span></a></li></ol></li></ol>
        
    </div>
</aside>
                
            </div>
        </div>
    </section>
    <footer class="main-footer">
    <div class="container">
        <div class="row">
        </div>
    </div>
</footer>
<a id="back-to-top" class="icon-btn hide">
    <i class="fa fa-chevron-up"></i>
</a>
    <div class="copyright">
    <div class="container">
        <div class="row">
            <div class="col-sm-12">
                <div class="busuanzi">
    
    访问量:
    <strong id="busuanzi_value_site_pv">
        <i class="fa fa-spinner fa-spin"></i>
    </strong>
    &nbsp; | &nbsp;
    访客数:
    <strong id="busuanzi_value_site_uv">
        <i class="fa fa-spinner fa-spin"></i>
    </strong>
    
</div>
            </div>
            <div class="col-sm-12">
                <span>Copyright &copy;
                    2019
                </span> |
                <span>
                    Powered by <a href="//hexo.io" class="copyright-links" target="_blank" rel="nofollow">Hexo</a>
                </span> |
                <span>
                    Theme by <a href="//github.com/shenliyang/hexo-theme-snippet.git" class="copyright-links" target="_blank" rel="nofollow">Snippet</a>
                </span>
            </div>
        </div>
    </div>
</div>


<script src="/assets/tagcanvas.min.js?rev=2.9"></script>
<script>
var tagOption = {
    textColour: '#444', // 字体颜色
    outlineMethod: 'block', // 选中模式
    outlineColour: '#FFDAB9', // 选中模式的颜色
    interval: 30 || 30, // 动画帧之间的时间间隔，值越大，转动幅度越大
    textHeight: 13,
    outlineRadius: 3,
    freezeActive: true || '', // 选中的标签是否继续滚动
    frontSelect: true || '', // 不选标签云后部的标签
    initial: [0.1, -0.1],
    depth: 0.5,
    decel: 0.95,
    maxSpeed: 0.03,
    reverse: true || '', // 是否反向触发
    fadeIn: 500, // 进入动画时间
    wheelZoom: false || '' // 是否启用鼠标滚轮
}
TagCanvas.Start('tag-cloud-3d', '', tagOption);
</script>


<script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>

<script src="/js/app.js?rev=@@hash"></script><!-- hexo-inject:begin --><!-- hexo-inject:end -->
</body>
</html>